// ignore_for_file: use_build_context_synchronously, invalid_use_of_protected_member, library_private_types_in_public_api

import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:image_picker/image_picker.dart';
import 'package:kmxy_base/kmxy_base.dart';
import 'package:kmxy_base/network/net.dart';
import 'package:kmxy_base/util/file_util.dart';
import 'package:kmxy_base/util/string_util.dart';
import 'package:kmxy_base/widget/mic_view.dart';
import 'package:video_thumbnail/video_thumbnail.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';

import 'cat_img_video_page_view.dart';
import 'media_select_view_menu_type.dart';
import 'media_type.dart';

typedef DataFun = Function(List allList, List imgList, List fileList);
typedef CallFileMap = Function(Map fileMap);
typedef UpFileFun = Function(String path, CallFileMap callFileMap);
typedef MediaUrlMakeFun = String Function(String mediaUrl);

class MediaSelectView extends StatefulWidget {
  /// 标题
  final String title;

  /// 内宽度
  final double? padding;

  /// 上传文件回调
  final UpFileFun? upFileFun;

  /// 回调
  final DataFun? dataFun;

  /// 1 拍摄照片、2 拍摄视频、3 选取照片、4 选取视频、5 文件选择
  final List<MediaSelectViewMenuType>? menuList;

  /// 文件选择后缀筛选
  final List<String>? fileAllowedExtensions;

  /// 数据
  final List? dataList;

  /// 媒体url处理回调
  final MediaUrlMakeFun mediaUrlMakeFun;

  /// 左边文字样式
  final TextStyle? leftTextStyle;

  /// 是否显示星号，默认：false
  final bool isStar;

  /// 星号样式，默认：Colors.red，16.sp
  final TextStyle? starStyle;

  /// 开始上传
  final Function? startUp;

  /// 结束上传
  final Function? endUp;

  /// 是否是签名图片
  final bool isSignature;

  const MediaSelectView({
    this.title = '附件',
    this.upFileFun,
    this.dataFun,
    this.menuList,
    this.padding,
    this.fileAllowedExtensions,
    required this.dataList,
    required this.mediaUrlMakeFun,
    this.leftTextStyle,
    this.isStar = false,
    this.starStyle,
    this.startUp,
    this.endUp,
    this.isSignature = false,
    Key? key,
  }) : super(key: key);

  @override
  _MediaSelectViewState createState() => _MediaSelectViewState();
}

class _MediaSelectViewState extends State<MediaSelectView> {
  List videoThumbnailList = [];
  @override
  void initState() {
    super.initState();
    initData();
  }

  @override
  void dispose() {
    super.dispose();
  }

  initData() async {
    for (Map item in widget.dataList ?? []) {
      if (item['link'] == null) {
        item['link'] = item['path'];
      }
      if (item['link'] == null) {
        item['link'] = item['name'];
      }
      if (MediaType.videoSuffixList
          .contains(FileUtil.getFileSuffix(item['link']).toLowerCase())) {
        String videoThumbnail =
            await getVideoThumbnail(widget.mediaUrlMakeFun(item['link']));
        videoThumbnailList.add(videoThumbnail);
      } else {
        videoThumbnailList.add('');
      }
      if (item['originalName'] != null) {
        item['name'] = item['originalName'];
      }
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    List gridList = [];
    List fileList = [];
    for (Map item in widget.dataList ?? []) {
      if (item['link'] == null) {
        item['link'] = item['path'];
      }
      if (item['link'] == null) {
        item['link'] = item['name'];
      }
      if (widget.isSignature) {
        fileList.add(item);
      } else {
        if (MediaType.imgSuffixList
                .contains(FileUtil.getFileSuffix(item['link']).toLowerCase()) ||
            MediaType.videoSuffixList
                .contains(FileUtil.getFileSuffix(item['link']).toLowerCase()) ||
            MediaType.audioSuffixList
                .contains(FileUtil.getFileSuffix(item['link']).toLowerCase())) {
          gridList.add(item);
        } else {
          fileList.add(item);
        }
      }
    }
    return Container(
      color: Colors.white,
      padding: EdgeInsets.all(widget.padding ?? 8.w),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          InkWell(
            onTap: () => add(gridList, fileList),
            child: Container(
              margin: EdgeInsets.only(bottom: 20.w),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    widget.title,
                    style: widget.leftTextStyle ??
                        TextStyle(color: Colors.grey, fontSize: 14.sp),
                  ),
                  widget.isStar
                      ? Text(
                          ' * ',
                          style: widget.starStyle ??
                              TextStyle(color: Colors.red, fontSize: 16.sp),
                        )
                      : Container(),
                  Expanded(child: Container()),
                  widget.dataFun == null
                      ? Container()
                      : Icon(Icons.add_to_photos_sharp, size: 20.sp)
                ],
              ),
            ),
          ),
          gridList.isEmpty
              ? Container()
              : Container(
                  padding: EdgeInsets.only(left: 10.w, right: 10.w),
                  child: GridView.builder(
                      itemCount: gridList.length,
                      //解决无限高度问题
                      shrinkWrap: true,
                      //禁用滑动事件
                      physics: const NeverScrollableScrollPhysics(),
                      //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
                      gridDelegate:
                          const SliverGridDelegateWithFixedCrossAxisCount(
                              //横轴元素个数
                              crossAxisCount: 3,
                              mainAxisSpacing: 20,
                              crossAxisSpacing: 20,
                              //子组件宽高长度比例
                              childAspectRatio: 1),
                      itemBuilder: (BuildContext context, int index) {
                        return Stack(
                          children: [
                            InkWell(
                              onTap: () => mediaClick(index, gridList),
                              child: mediaView(gridList[index], index),
                            ),
                            widget.dataFun == null
                                ? Container()
                                : Positioned(
                                    right: 5.w,
                                    top: 5.w,
                                    child: InkWell(
                                      onTap: () =>
                                          delImg(index, gridList, fileList),
                                      child: Icon(
                                        Icons.delete_outline,
                                        color: Colors.red,
                                        size: 24.w,
                                      ),
                                    ),
                                  ),
                          ],
                        );
                      }),
                ),
          gridList.isEmpty ? Container() : SizedBox(height: 10.w),
          fileList.isEmpty
              ? Container()
              : widget.isSignature
                  ? Container(
                      padding: EdgeInsets.only(left: 10.w, right: 10.w),
                      child: GridView.builder(
                          itemCount: fileList.length,
                          //解决无限高度问题
                          shrinkWrap: true,
                          //禁用滑动事件
                          physics: const NeverScrollableScrollPhysics(),
                          //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
                          gridDelegate:
                              const SliverGridDelegateWithFixedCrossAxisCount(
                                  //横轴元素个数
                                  crossAxisCount: 2,
                                  mainAxisSpacing: 20,
                                  crossAxisSpacing: 20,
                                  //子组件宽高长度比例
                                  childAspectRatio: 3),
                          itemBuilder: (BuildContext context, int index) {
                            return signatureView(fileList[index], index, fileList);
                          }),
                    )
                  : Column(
                      children: List.generate(
                          fileList.length,
                          (index) => fileItemView(
                              fileList[index], index, gridList, fileList)),
                    ),
        ],
      ),
    );
  }

  Widget signatureView(Map itemData, int index, List fileList) {
    return InkWell(
      onTap: () => mediaClick(index, fileList),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: CachedNetworkImage(
            width: double.infinity,
            height: 130.w,
            imageUrl: widget.mediaUrlMakeFun(itemData['link']),
            placeholder: (context, url) => Container(
                width: double.infinity,
                height: 130.w,
                color: Colors.grey.shade50),
            errorWidget: (context, url, error) => const Icon(Icons.error),
            fit: BoxFit.fill),
      ),
    );
  }

  Widget fileItemView(Map itemData, int index, List gridList, List fileList) {
    return InkWell(
      onTap: () => fileClick(itemData),
      child: Container(
        margin: EdgeInsets.symmetric(vertical: 5.w, horizontal: 10.w),
        padding: EdgeInsets.all(5.w),
        decoration: BoxDecoration(
          color: Colors.grey.shade200,
          // 圆角设置
          borderRadius: BorderRadius.circular(8),
        ),
        child: Row(
          children: [
            const Icon(Icons.file_copy_outlined, size: 20, color: Colors.green),
            SizedBox(width: 10.w),
            Expanded(
              child: Text(
                '${itemData['name'] ?? ''}',
                style: TextStyle(fontSize: 12.w),
              ),
            ),
            widget.dataFun == null
                ? Container()
                : InkWell(
                    onTap: () => delFile(index, gridList, fileList),
                    child: const Icon(Icons.delete_outline,
                        size: 20, color: Colors.red),
                  ),
          ],
        ),
      ),
    );
  }

  Widget mediaView(Map itemData, int index) {
    if (MediaType.videoSuffixList
        .contains(FileUtil.getFileSuffix(itemData['link']).toLowerCase())) {
      return Container(
        width: double.infinity,
        height: double.infinity,
        decoration: BoxDecoration(
          color: Colors.black,
          // 圆角设置
          borderRadius: BorderRadius.circular(8),
        ),
        child: Stack(alignment: Alignment.center, children: [
          videoThumbnailList.length > index
              ? ClipRRect(
                  borderRadius: BorderRadius.circular(8),
                  child: videoThumbnailList[index].isNotEmpty
                      ? Image.file(
                          File(videoThumbnailList[index]),
                          height: double.infinity,
                          width: double.infinity,
                          fit: BoxFit.cover,
                        )
                      : Container(),
                )
              : Container(),
          const Icon(
            Icons.play_arrow_rounded,
            size: 60,
            color: Colors.white,
          ),
        ]),
      );
    }

    if (MediaType.audioSuffixList
        .contains(FileUtil.getFileSuffix(itemData['link']).toLowerCase())) {
      return Container(
        width: double.infinity,
        height: double.infinity,
        decoration: BoxDecoration(
          color: Colors.black,
          // 圆角设置
          borderRadius: BorderRadius.circular(8),
        ),
        child: Stack(
          alignment: Alignment.center,
          children: [
            const Icon(
              Icons.volume_up_rounded,
              size: 46,
              color: Colors.white,
            ),
            Positioned(
              top: 8.w,
              left: 8.w,
              child: Text(
                '${itemData['time'] ?? '0'}s',
                style: const TextStyle(color: Colors.white),
              ),
            ),
          ],
        ),
      );
    }

    return ClipRRect(
      borderRadius: BorderRadius.circular(8),
      child: CachedNetworkImage(
          width: double.infinity,
          height: double.infinity,
          imageUrl: widget.mediaUrlMakeFun(itemData['link']),
          placeholder: (context, url) => Container(
              width: double.infinity,
              height: double.infinity,
              color: Colors.grey.shade50),
          errorWidget: (context, url, error) => const Icon(Icons.error),
          fit: BoxFit.cover),
    );
  }

  add(List gridList, List fileList) {
    if (widget.dataFun == null) {
      return;
    }
    List<MediaSelectViewMenuType> menuList = widget.menuList ??
        [
          MediaSelectViewMenuType.galleryImage,
          MediaSelectViewMenuType.galleryVideo,
          MediaSelectViewMenuType.cameraImage,
          MediaSelectViewMenuType.cameraVideo,
          MediaSelectViewMenuType.audio,
          MediaSelectViewMenuType.file,
        ];
    FocusManager.instance.primaryFocus?.unfocus();
    List btnList = [];
    if (menuList.contains(MediaSelectViewMenuType.cameraImage)) {
      btnList.add({
        'name': '拍摄照片',
        'fun': () async {
          XFile? xFile = await FileUtil.getImageOrVideo(context, 0);
          Navigator.pop(context);
          if (xFile != null) {
            if (widget.upFileFun != null) {
              if (widget.startUp != null) {
                widget.startUp!();
              }
              widget.upFileFun!(xFile.path, (Map fileMap) {
                makeFileData(fileMap);
                xFile = null;
                gridList.add(fileMap);
                videoThumbnailList.add('');
                setState(() {});
                List tempList = [];
                tempList.addAll(gridList);
                tempList.addAll(fileList);
                if (widget.dataFun != null) {
                  widget.dataFun!(tempList, gridList, fileList);
                }
                if (widget.endUp != null) {
                  widget.endUp!();
                }
              });
            }
          }
        }
      });
    }
    if (menuList.contains(MediaSelectViewMenuType.cameraVideo)) {
      btnList.add({
        'name': '拍摄视频',
        'fun': () async {
          XFile? xFile = await FileUtil.getImageOrVideo(context, 2);
          Navigator.pop(context);
          if (xFile != null) {
            if (widget.upFileFun != null) {
              if (widget.startUp != null) {
                widget.startUp!();
              }
              widget.upFileFun!(xFile.path, (Map fileMap) async {
                makeFileData(fileMap);
                xFile = null;
                gridList.add(fileMap);
                String videoThumbnail = await getVideoThumbnail(
                    widget.mediaUrlMakeFun(fileMap['link']));
                videoThumbnailList.add(videoThumbnail);
                setState(() {});
                List tempList = [];
                tempList.addAll(gridList);
                tempList.addAll(fileList);
                if (widget.dataFun != null) {
                  widget.dataFun!(tempList, gridList, fileList);
                }
                if (widget.endUp != null) {
                  widget.endUp!();
                }
              });
            }
          }
        }
      });
    }
    if (menuList.contains(MediaSelectViewMenuType.galleryImage)) {
      btnList.add({
        'name': '选取图片',
        'fun': () async {
          final List<AssetEntity> assetEntityList =
              await AssetPicker.pickAssets(
                    context,
                    pickerConfig: const AssetPickerConfig(
                        maxAssets: 9,
                        gridCount: 4,
                        requestType: RequestType.image),
                  ) ??
                  [];
          Navigator.pop(context);
          int upCount = 0;
          if (assetEntityList.isNotEmpty && widget.startUp != null) {
            widget.startUp!();
          }
          for (AssetEntity assetEntity in assetEntityList) {
            File? file = await assetEntity.file;
            if (file != null) {
              if (widget.upFileFun != null) {
                widget.upFileFun!(file.path, (Map fileMap) async {
                  makeFileData(fileMap);
                  upCount++;
                  gridList.add(fileMap);
                  videoThumbnailList.add('');
                  setState(() {});
                  List tempList = [];
                  tempList.addAll(gridList);
                  tempList.addAll(fileList);
                  if (widget.dataFun != null) {
                    widget.dataFun!(tempList, gridList, fileList);
                  }
                  if (assetEntityList.length == upCount &&
                      widget.endUp != null) {
                    widget.endUp!();
                  }
                });
              }
            }
          }
        }
      });
    }
    if (menuList.contains(MediaSelectViewMenuType.galleryVideo)) {
      btnList.add({
        'name': '选取视频',
        'fun': () async {
          final List<AssetEntity> assetEntityList =
              await AssetPicker.pickAssets(
                    context,
                    pickerConfig: const AssetPickerConfig(
                        maxAssets: 9,
                        gridCount: 4,
                        requestType: RequestType.video),
                  ) ??
                  [];
          Navigator.pop(context);
          int upCount = 0;
          if (assetEntityList.isNotEmpty && widget.startUp != null) {
            widget.startUp!();
          }
          for (AssetEntity assetEntity in assetEntityList) {
            File? file = await assetEntity.file;
            if (file != null) {
              if (widget.upFileFun != null) {
                widget.upFileFun!(file.path, (Map fileMap) async {
                  makeFileData(fileMap);
                  upCount++;
                  gridList.add(fileMap);
                  String videoThumbnail = await getVideoThumbnail(
                      widget.mediaUrlMakeFun(fileMap['link']));
                  videoThumbnailList.add(videoThumbnail);
                  setState(() {});
                  List tempList = [];
                  tempList.addAll(gridList);
                  tempList.addAll(fileList);
                  if (widget.dataFun != null) {
                    widget.dataFun!(tempList, gridList, fileList);
                  }
                  if (assetEntityList.length == upCount &&
                      widget.endUp != null) {
                    widget.endUp!();
                  }
                });
              }
            }
          }
        }
      });
    }
    if (menuList.contains(MediaSelectViewMenuType.audio)) {
      btnList.add({
        'name': '语音录制',
        'fun': () async {
          Navigator.pop(context);
          showModalBottomSheet(
              context: context,
              builder: (builder) {
                return MicView((String micPath, double time) {
                  micStop(micPath, time, gridList, fileList);
                });
              });
        }
      });
    }
    if (menuList.contains(MediaSelectViewMenuType.file)) {
      btnList.add({
        'name': '选取文件',
        'fun': () async {
          FilePickerResult? result = await FilePicker.platform.pickFiles(
            type: FileType.any,
            allowedExtensions: widget.fileAllowedExtensions ?? [],
          );
          Navigator.pop(context);
          if (result != null) {
            PlatformFile file = result.files.first;
            if (file.size > 50 * 1024 * 1024) {
              return '文件大于50MB'.toast();
            }
            if (result.files.single.path != null) {
              if (widget.upFileFun != null) {
                if (widget.startUp != null) {
                  widget.startUp!();
                }
                widget.upFileFun!(result.files.single.path!, (Map fileMap) {
                  makeFileData(fileMap);
                  fileList.add(fileMap);
                  setState(() {});
                  List tempList = [];
                  tempList.addAll(gridList);
                  tempList.addAll(fileList);
                  if (widget.dataFun != null) {
                    widget.dataFun!(tempList, gridList, fileList);
                  }
                  if (widget.endUp != null) {
                    widget.endUp!();
                  }
                });
              }
            }
          }
        }
      });
    }

    showModalBottomSheet(
        context: context,
        builder: (builder) {
          return SafeArea(
            child: Container(
              padding: EdgeInsets.only(bottom: 10.w),
              height: btnList.length * 55.w,
              color: Colors.transparent,
              child: Container(
                decoration: const BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(10.0),
                        topRight: Radius.circular(10.0))),
                child: Column(
                  children: List.generate(btnList.length, (index) {
                    return InkWell(
                      onTap: btnList[index]['fun'],
                      child: Container(
                        alignment: Alignment.center,
                        width: double.infinity,
                        height: 50,
                        child: Text(
                          btnList[index]['name'],
                          textAlign: TextAlign.center,
                          style: const TextStyle(
                            fontSize: 18,
                            color: Color(0xFF567DF4),
                          ),
                        ),
                      ),
                    );
                  }),
                ),
              ),
            ),
          );
        });
  }

  micStop(String micPath, double time, List gridList, List fileList) {
    if (time < 2) {
      return '说话时间太短'.toast();
    }
    if (widget.upFileFun != null) {
      if (widget.startUp != null) {
        widget.startUp!();
      }
      widget.upFileFun!(micPath, (Map fileMap) {
        makeFileData(fileMap);
        fileMap['time'] = time.toInt();
        gridList.add(fileMap);
        videoThumbnailList.add('');
        setState(() {});
        List tempList = [];
        tempList.addAll(gridList);
        tempList.addAll(fileList);
        if (widget.dataFun != null) {
          widget.dataFun!(tempList, gridList, fileList);
        }
        Navigator.pop(context);
        if (widget.endUp != null) {
          widget.endUp!();
        }
      });
    }
  }

  /// 图片视频点击
  mediaClick(int index, List gridList) async {
    FocusManager.instance.primaryFocus?.unfocus();
    Navigator.push(context, MaterialPageRoute(
      builder: (_) {
        return CatImgVideoPageView(
            dataList: gridList,
            index: index,
            mediaUrlMakeFun: widget.mediaUrlMakeFun);
      },
    ));
  }

  fileClick(Map itemData) async {
    FocusManager.instance.primaryFocus?.unfocus();
    String fileDir = await FileUtil.getFilesDir();
    File file = File('$fileDir/${FileUtil.getFileName(itemData['link'])}');
    // 文件是否已经下载到本地
    if (file.existsSync()) {
      // 使用wps打开
      bool isAvilible = await KmxyBase.isAvilible('cn.wps.moffice_eng');
      if (isAvilible) {
        await KmxyBase.openWps(file.path);
      } else {
        return '请安装 WPS Office，再查看文件'.toast();
      }
    } else {
      EasyLoading.show(status: '下载中...');
      Net.downloadTemp(widget.mediaUrlMakeFun(itemData['link']),
          '$fileDir/${FileUtil.getFileName(itemData['link'])}',
          progress: (int progress) {}, finish: (String savePath) async {
        EasyLoading.dismiss();
        // 使用wps打开
        bool isAvilible = await KmxyBase.isAvilible('cn.wps.moffice_eng');
        if (isAvilible) {
          await KmxyBase.openWps(savePath);
        } else {
          return '请安装 WPS Office，再查看文件'.toast();
        }
      }, error: (e) {
        EasyLoading.dismiss();
      });
    }
  }

  /// 删除图片、视频
  delImg(int index, List gridList, List fileList) {
    setState(() {
      gridList.removeAt(index);
    });
    List tempList = [];
    tempList.addAll(gridList);
    tempList.addAll(fileList);
    if (widget.dataFun != null) {
      widget.dataFun!(tempList, gridList, fileList);
    }
  }

  /// 删除文件
  delFile(int index, List gridList, List fileList) {
    setState(() {
      fileList.removeAt(index);
    });
    List tempList = [];
    tempList.addAll(gridList);
    tempList.addAll(fileList);
    if (widget.dataFun != null) {
      widget.dataFun!(tempList, gridList, fileList);
    }
  }

  Future<String> getVideoThumbnail(String url) async {
    String savePath =
        '${await FileUtil.getCacheDir()}/${FileUtil.getFileName(url.substring(0, url.indexOf('?')))}';
    await Net.tempDio.download(
      url,
      savePath,
    );
    if (!await File(savePath).exists()) {
      return '';
    }
    String? fileName = await VideoThumbnail.thumbnailFile(
        video: savePath,
        thumbnailPath: await FileUtil.getCacheDir(),
        timeMs: 1000);
    return fileName ?? '';
  }

  makeFileData(Map fileMap) {
    fileMap.remove('domain');
    fileMap.remove('attachId');
    fileMap['name'] = fileMap['originalName'];
    fileMap.remove('originalName');
    fileMap['time'] = 0;
  }
}
